package com.yt.web.unit;

import com.haier.common.util.StringUtil;

public class KeywordEncoder {
    private static org.apache.log4j.Logger logger        = org.apache.log4j.LogManager
                                                             .getLogger(KeywordEncoder.class);

    final static String                    alphabet      = "abcdefghijklmnopqrstuvwxyz";      //"bceflmndoghqarijpkstuvwxyz"; // "zyxwvutsrqponmlkjihgfedcba";
    final static String                    complementary = "X";
    final static String                    separator     = "_";

    /**
     * 单个字符Base26编码
     * @param number
     * @return
     */
    private static String asciiEncode(long number) {
        number = Math.abs(number);
        StringBuilder b = new StringBuilder();
        assert (number > 0);
        do {
            long div = (number / 26);
            int mod = (int) (number % 26);
            b.append(alphabet.charAt(mod));
            number = div;
        } while (number != 0);
        return b.reverse().toString();
    }

    static int error(String s) {
        throw new RuntimeException(s);
    }

    /**
     * Base26解码
     * @param number
     * @return
     */
    private static long asciiDecode(String string) {
        if (StringUtil.isEmpty(string, true))
            throw new IllegalArgumentException("the decode param is not null");
        if (!string.matches("[a-z]*")) {
            throw new IllegalArgumentException("Not a base26 representation");
        }
        final int l = string.length();
        long answer = 0;
        long mul = 1;
        for (int i = 0; i < l; i++) {
            int val = (int) string.charAt(i);
            int num = (val >= 97 && val <= 122) ? (val - 97)
                : (val >= 65 && val <= 90) ? (val - 65) : error("bad format");
            answer += num * mul;
            mul *= 26;
        }
        return answer;
    }

    public static String stringEncode(String str) {
        try {
            char[] chars = str.toCharArray();
            StringBuffer sb = new StringBuffer();
            int prevType = 0;
            int currType = 0;
            for (int i = 0; i < chars.length; i++) {
                char c = chars[i];
                CharType charType = checkType(c);
                if (charType == CharType.LETTER || charType == CharType.NUM) {
                    currType = 1;
                    if (sb.length() != 0 && prevType != currType)
                        sb.append("_");
                    sb.append(c);
                    prevType = 1;
                } else if (charType == CharType.DELIMITER || charType == CharType.OTHER) {
                    currType = 2;
                    if (sb.length() == 0 || prevType != currType)
                        sb.append(separator);
                    sb.append(asciiEncode((int) c));
                    sb.append(complementary);
                    prevType = 2;
                } else {
                    currType = 2;
                    if (sb.length() == 0 || prevType != currType)
                        sb.append(separator);
                    sb.append(asciiEncode((int) c));
                    prevType = 2;
                }
            }
            sb.append("-se");
            return sb.toString();
        } catch (Exception e) {
            logger.error("[search-word-encode]:关键词编码异常", e);
            throw new RuntimeException("[search-word-encode]:关键词编码异常");
        }

    }

    public static String stringDecode(String str) {
        int index = str.lastIndexOf("-se");
        if (index == -1) {
            throw new RuntimeException("[search-word-decode]:非法字符串,无法解码!");
        }
        try {
            String newStr = str.substring(0, index);
            String[] arrStr = newStr.split(separator);
            StringBuffer sb = new StringBuffer();
            sb.append(arrStr[0]);
            for (int i = 1; i < arrStr.length; i++) {
                String item = arrStr[i];
                if (i % 2 == 1) {
                    String[] asciiStr = item.split(complementary);
                    for (int j = 0; j < asciiStr.length; j++) {
                        String string = asciiStr[j];
                        //                  int number = string.length();
                        int beginIndex = 0;
                        while (string.length() - beginIndex >= 2) {
                            int split_len = (string.length() - beginIndex < 4) ? string.length()
                                                                                 - beginIndex : 4;
                            String k_str = string.substring(beginIndex, beginIndex + split_len);
                            sb.append((char) asciiDecode(new StringBuilder(k_str).reverse()
                                .toString()));
                            beginIndex = beginIndex + split_len;
                        }
                    }
                } else {
                    sb.append(item);
                }
            }
            return sb.toString();
        } catch (Exception e) {
            logger.error("[search-word-decode]:字符串解码异常", e);
            throw new RuntimeException("[search-word-decode]:字符串解码异常");
        }

    }

    enum CharType {
        DELIMITER, // 非字母截止字符，例如，．）（　等等　（ 包含U0000-U0080）
        NUM, // 2字节数字１２３４
        LETTER, // gb2312中的，例如:ＡＢＣ，2字节字符同时包含 1字节能表示的 basic latin and latin-1
        OTHER, // 其他字符
        CHINESE; // 中文字
    }

    /**
     * 判断输入char类型变量的字符类型
     * 
     * @param c
     *            char类型变量
     * @return CharType 字符类型
     */
    private static CharType checkType(char c) {
        CharType ct = null;
        // 中文，编码区间0x4e00-0x9fbb
        if ((c >= 0x4e00) && (c <= 0x9fbb)) {
            ct = CharType.CHINESE;
        }
        // Halfwidth and Fullwidth Forms， 编码区间0xff00-0xffef
        else if ((c >= 0xff00) && (c <= 0xffef)) { // 2字节英文字
            if (((c >= 0xff21) && (c <= 0xff3a)) || ((c >= 0xff41) && (c <= 0xff5a))) {
                ct = CharType.LETTER;
            }
            // 2字节数字
            else if ((c >= 0xff10) && (c <= 0xff19)) {
                ct = CharType.NUM;
            }
            // 其他字符，可以认为是标点符号
            else
                ct = CharType.DELIMITER;
        }
        // basic latin，编码区间 0000-007f
        else if ((c >= 0x0021) && (c <= 0x007e)) { // 1字节数字
            if ((c >= 0x0030) && (c <= 0x0039)) {
                ct = CharType.NUM;
            } // 1字节字符
            else if (((c >= 0x0041) && (c <= 0x005a)) || ((c >= 0x0061) && (c <= 0x007a))) {
                ct = CharType.LETTER;
            }
            // 其他字符，可以认为是标点符号
            else
                ct = CharType.DELIMITER;
        }
        // latin-1，编码区间0080-00ff
        else if ((c >= 0x00a1) && (c <= 0x00ff)) {
            if ((c >= 0x00c0) && (c <= 0x00ff)) {
                ct = CharType.LETTER;
            } else
                ct = CharType.DELIMITER;
        } else
            ct = CharType.OTHER;

        return ct;
    }

    public static void main(String[] args) throws Exception {
        System.out.println(stringEncode("中文_ABや3F한"));
        System.out.println(stringDecode(stringEncode("中文_ABや3F한")));
        System.out.println(stringEncode(""));
        System.out.println(stringDecode(stringEncode("")));
    }

}
